from shutil import copyfile, copytree, rmtree
from sys import exit
import struct
import sys, traceback
import os
from os import path, system, remove
import mmap
import codecs

backup_path = ".\\backup"
patch_path = ".\\patch"
target_path = ".."

def format_file(file):
    try:
        toformat = "unix2dos"
        print('Formatting %s:\t%s' % (toformat, file))
        if not os.path.isfile(file):
            print('ERROR: %s invalid normal file' % file)
            return
        with open(file, 'r') as fd:
            tmpfile = open(file+toformat, 'w')
            for line in fd:
                line = line.replace('\r', '')
                tmpfile.write(line)
            tmpfile.close()
            fd.close()
            os.remove(file)
            os.rename(file+toformat, file)
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc())

def patch_file(type, pathdest, pathdest2, filename, srcfile=None, tgtpath=target_path):
    try:
        print("patch %s" % filename)
        if None == srcfile or "" == srcfile:
            srcfile = filename
        if 1 == type:
            print("%s\\%s%s" % (patch_path, pathdest, srcfile), "%s\\%s%s" % (tgtpath, pathdest2, filename))
            copyfile("%s\\%s%s" % (patch_path, pathdest, srcfile), "%s\\%s%s" % (tgtpath, pathdest2, filename))
        elif 2 == type:
            print("%s\\%s%s" % (patch_path, pathdest, srcfile), "%s\\%s%s" % (tgtpath, pathdest2, filename))
            if path.exists("%s\\%s%s" % (tgtpath, pathdest2, filename)) or "*" == filename:
                system("xcopy \"%s\" \"%s\" /s /e /y>NUL" % ("%s\\%s%s" % (patch_path, pathdest, srcfile), "%s\\%s%s" % (tgtpath, pathdest2, filename)))
            else:
                copytree("%s\\%s%s" % (patch_path, pathdest, srcfile), "%s\\%s%s" % (tgtpath, pathdest2, filename))
    except IOError as e:
        print("Unable to restore file. %s" % e)
        print(traceback.format_exc())
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc())

def restore_file(type, pathdest, filename, tgtpath=target_path):
    try:
        print("restore %s" % filename)
        if 1 == type:
            #print("%s\\%s" % (backup_path, filename), "%s\\%s%s" % (tgtpath, pathdest, filename))
            copyfile("%s\\%s" % (backup_path, filename), "%s\\%s%s" % (tgtpath, pathdest, filename))
        elif 2 == type:
            #print("%s\\%s%s" % (tgtpath, pathdest, filename))
            if path.exists("%s\\%s%s" % (tgtpath, pathdest, filename)):
                rmtree("%s\\%s%s" % (tgtpath, pathdest, filename))
        elif 3 == type:
            #print("%s\\%s%s" % (tgtpath, pathdest, filename))
            if path.exists("%s\\%s%s" % (tgtpath, pathdest, filename)):
                os.remove("%s\\%s%s" % (tgtpath, pathdest, filename))
    except IOError as e:
        print("Unable to restore file. %s" % e)
        print(traceback.format_exc())
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc())

def hack_dll(filename, hackbin):
    try:
        print("hack %s" % filename)
        with open(filename, "r+b") as f1:
            for offset in hackbin:
                f1.seek(offset)
                f1.write(struct.pack("B", hackbin[offset]))
            f1.close()
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc())

def hack_dll_4(filename, hackbin, basevalue=0):
    try:
        print("hack %s" % filename)
        with open(filename, "r+b") as f1:
            for offset in hackbin:
                f1.seek(offset)
                f1.write(struct.pack("I", basevalue + hackbin[offset]))
            f1.close()
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc())

def hack_dll_batch(filename, hackbin, offset):
    try:
        print("hack %s" % filename)
        with open(filename, "r+b") as f1:
            for value in hackbin:
                f1.seek(offset)
                f1.write(struct.pack("B", value))
                offset += 1
            f1.close()
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc())

def append_dll(filename, value, len):
    try:
        print("append %s" % filename)
        with open(filename, "a+b") as f1:
            while 0 < len:
                f1.write(struct.pack("B", value))
                len -= 1
            f1.close()
    except:
        print("Unexpected error:", sys.exc_info())
        print(traceback.format_exc()) 

def dll_seek(filename, hackbin, offset=0):
    try:
        print("seek %s" % filename)
        with open(filename, "r+b") as f1:
            mm = mmap.mmap(f1.fileno(), 0)
            return mm.find(hackbin, offset)
    except:
       print("Unexpected error:", sys.exc_info())
       print(traceback.format_exc())
       return -1

def combine_file(src_file, dst_file, patch_file, skip_line=0):
    try:
        print("combine %s" % src_file)
        copyfile(src_file, dst_file)
        with codecs.open(dst_file, 'r', encoding='utf-8') as f1:
            content = f1.read().rstrip("\r\n")
            f1.close()
            f2 = codecs.open(patch_file, 'r', encoding='utf-8')
            if f2:
                tempcont = "\r\n".join(f2.read().rstrip("\r\n").split("\r\n")[skip_line:])
                f2.close()
            else:
                tempcont = ""
            content = "%s\r\n%s\r\n" % (content, tempcont)
            f2 = codecs.open(dst_file, 'w', encoding='utf-8')
            if f2:
                f2.write(content)
                f2.close()
        copyfile(dst_file, src_file)
    except:
       print("Unexpected error:", sys.exc_info())
       print(traceback.format_exc())